package com.vcourse.service.admin.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.vcourse.commons.result.ResultCodeEnum;
import com.vcourse.oauth2.utils.JwtTokenUtils;
import com.vcourse.service.admin.bo.AdminUserDetails;
import com.vcourse.service.admin.entity.User;
import com.vcourse.service.admin.mapper.PermissionMapper;
import com.vcourse.service.admin.mapper.UserMapper;
import com.vcourse.service.admin.service.UserService;
import com.vcourse.service.base.exception.CustomException;
import com.vcourse.service.base.service.RedisService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;

/**
 * <p>
 * 用户表 服务实现类
 * </p>
 *
 * @author testjava
 * @since 2020-01-12
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    @Autowired
    private RedisService redisService;
    @Autowired
    private JwtTokenUtils jwtTokenUtil;
    @Resource
    private PermissionMapper permissionMapper;
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Value("${redis.database}")
    private String REDIS_DATABASE;
    @Value("${redis.expire.common}")
    private Long REDIS_EXPIRE;
    @Value("${redis.key.admin}")
    private String REDIS_KEY_ADMIN;
    @Value("${redis.key.resourceList}")
    private String REDIS_KEY_RESOURCE_LIST;

    @Override
    public User selectByUsername(String username) {
        return baseMapper.selectOne(new QueryWrapper<User>().eq("username", username));
    }

    @Override
    public String login(String username, String password) {
        String token = null;
        //密码需要客户端加密后传递
        try {
            UserDetails userDetails = loadUserByUsername(username);
            if(!passwordEncoder.matches(password, userDetails.getPassword())){
                throw new BadCredentialsException("密码不正确");
            }
            UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
            SecurityContextHolder.getContext().setAuthentication(authentication);
            token = jwtTokenUtil.generateToken(userDetails);
        } catch (AuthenticationException e) {
            log.warn("登录异常:" + e.getMessage());
            throw new CustomException(ResultCodeEnum.LOGIN_ERROR);
        }
        return token;
    }

    @Override
    public List<String> getPermissionList(String userId, String username) {
        String key = REDIS_DATABASE + ":" + REDIS_KEY_RESOURCE_LIST + ":" + username;
        // 从redis中获取
        List<String> permissionValueList = (List<String>) redisService.get(key);
        if (CollUtil.isNotEmpty(permissionValueList)) {
            return  permissionValueList;
        }
        // 否则从数据库查
        permissionValueList = permissionMapper.selectPermissionValueByUserId(userId);
        if (CollUtil.isNotEmpty(permissionValueList)) {
            // 缓存到数据库中
            redisService.set(key, permissionValueList, REDIS_EXPIRE);
        }
        return permissionValueList;
    }

    @Override
    public UserDetails loadUserByUsername(String username) {
        // 获取用户信息
        User user = selectByUsername(username);
        if (user == null) {
            throw new CustomException(ResultCodeEnum.LOGIN_MOBILE_ERROR);
        }
        List<String> permissionValueList = getPermissionList(user.getId(), username);
        return new AdminUserDetails(user, permissionValueList);
    }
}
